#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Copyright (c) 2011 - 2013 Stefano Mazzucco <stefano -at- curso.re>
# All rights reserved.
#
# This file is part of Crystal Ball Plus.
#
# Crystal Ball Plus is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Crystal Ball Plus is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Crystal Ball Plus.  If not, see <http://www.gnu.org/licenses/>.

# file IO operations

import sys
import os
import numpy as np

newline = ('\n', '\r\n', '\r')
comment = '#'
special = '##'

# try to determine the OS and set the newline character
if 'win' in sys.platform:
    # Windows
    nl = '\r\n'
elif 'darwin' in sys.platform:
    # Mac
    nl = '\r'
else:
    # *nix
    nl = '\n'

def overwrite(fname):
    # original borrowed from EELSLab lib/utils_varia.py changeset:d1a3392f0d79
    # http://www.eelslab.org
    """ If file exists, ask for overwriting and return True or False,
    else return True.
    """
    if os.path.isfile(fname):
        message = "Overwrite '%s' (y/n)?\n" % fname
        answer = raw_input(message)
        answer = answer.lower()
        while (answer != 'y') and (answer != 'n'):
            print('Please answer y or n.')
            answer = raw_input(message)
        if answer.lower() == 'y':
            return True
        elif answer.lower() == 'n':
            return False
    else:
        return True

def newname(fname):
    """If 'fname' exists in the current directory, ask for a new (base)name
    and, of course, return it.

    """
    cdir = os.path.split(fname)[0]
    base = os.path.split(fname)[1]
    if os.path.isfile(fname):
        if overwrite(fname):
            return fname
        else:
            message = 'Please choose a new name.\n'
            answer = raw_input(message)
            nname = os.path.join(cdir, answer)
            return newname(nname)
    else:
        return fname

def read_single_column(fp):
    # this is a general function and will be moved to a different module
    """Read a one-column file and returns the contents
    as a numpy array of floats"""
    if type(fp) is file:
        if not fp.closed:
            out = []
            for line in fp.readlines():
                val = line.strip('\r\n')
                out.append(float(val))
            return out
    elif type(fp) is str:
        with open(fp) as f:
            out = []
            for line in f.readlines():
                val = line.strip('\r\n')
                out.append(float(val))
            return np.asarray(out)

def read_crystal(fp, sep=None):
    # OBSLETE
    """Read a 3-column file containing:
    d-spacings, hkl planes, relative intensity.

    Separator sep is whitespace if not specified.

    Empty lines and lines beginning with # are skipped.

    Accepts a string (file name) or a file object.

    Returns a structured numpy array
    dtype={'names':['d', 'hkl', 'Int'],
    'formats':['f4', '|S10', 'f4']})

    E.g. out['d'] will return only the d-spacings
    """

    def crystal(f, sep=None):
        """utility function, f is a file object"""
        if not f.closed:
            out = []
            for line in f.readlines():
                if line[:2] not in newline and line[0] != comment:
                    val = line.strip('\r\n').split(sep)
                    val[0] = float(val[0])
                    val[2] = float(val[2])
                    val = tuple(val)
                    out.append(val)
            # create a structured array
            # http://docs.scipy.org/doc/numpy/user/basics.rec.html
            # values can be called with key name
            # e.g. out['d'] will return only the d-spacings
            out = np.asarray(out,
                             dtype={'names':['d', 'hkl', 'Int'],
                                    'formats':['f4', '|S10', 'f4']})
            return out
    # this is the "main"
    if type(fp) is file:
        return crystal(fp, sep)
    elif type(fp) is str:
        with open(fp, 'read') as f:
            return crystal(f, sep)

def read_exp_diffractogram(f, sep=None):
    # OBSOLETE
    """Read measured diffractogram data from file (or file object) f.
    Returns the 3-N-tuple (d-spacings, angles, intensities)

    The file that is being read MUST have two or three columns containing the
    following information:

    d_spacings;    angles;   intensities (optional)

    If sep is not specified or is None, any whitespace string is a separator
    and empty strings are removed.

    Blank lines and comments (lines preceeded by '#') are ignored.

    Special comments (lines preceeded by '##') are printed to screen.
    """
    if not hasattr(f, 'closed'):
        try:
            fp = open(f, 'r')
        except:
            print('Error while opening %s' % fp)
            return
    else:
        fp = f
    if not fp.closed:
        # newline = ('\n', '\r\n')
        # comment = '#'
        # special = '##'
        d_spacings = []
        angles = []
        intensities = []
        d_col, a_col, i_col = (None, None, None)
        try:
            for line in fp.readlines():
                if line[:2] not in newline and (line[0] != comment
                                                or line[:2] == special):
                    if special in line:
                        line = line.lstrip(special).strip('\r\n')
                        print(line)
                    else:
                        line = line.strip('\r\n').split(sep)
                        if line: # skip empty lines
                            d_spacings.append(float(line[0]))
                            angles.append(float(line[1]))
                            if len(line) == 3:
                                intensities.append(float(line[2]))
        except:
            err = sys.exc_info()[1]
            print('Error %s while reading %s' % (err, fp.name))
        finally:
            fp.close()
        if intensities:
            # print('d_spacings;    angles;   intensities read')
            return np.asarray((d_spacings, angles, intensities))
        else:
            # print('d_spacings;    angles read')
            return np.asarray((d_spacings, angles))

